 
import { StationNetwork } from "GameLoop/Path/StationNetwork";
 
import { planningHelper } from "./planningHelper";
import { ZipRoomPlan } from "utils/plan/ZipRoomPlan";
import { Matrix3 } from "GameLoop/Execution/FormationManager/types";
import { PositionHelper } from "utils/position/PositionHelper";
 
const LEFTSHIFT = 2;

export const ENone:number = 0 << LEFTSHIFT;
export const   EMyWall:number = 1 << LEFTSHIFT;
export const  EContainer:number = 2 << LEFTSHIFT;
export const  EExtension:number = 3 << LEFTSHIFT;
export const   ELab:number = 4 << LEFTSHIFT;
export const   ELink:number = 5 << LEFTSHIFT;
export const   EObserver:number = 6 << LEFTSHIFT;
export const  ERampart:number = 7 << LEFTSHIFT;
export const    ERoad:number = 8 << LEFTSHIFT;
export const   ESpawn:number = 9 << LEFTSHIFT;
export const   EStorage:number = 10 << LEFTSHIFT;
export const  ETermial:number = 11 << LEFTSHIFT;
export const  ETower:number = 12 << LEFTSHIFT;
export const  EFactory:number = 13 << LEFTSHIFT;
export const EController:number = 14 << LEFTSHIFT;
export const  ESource:number = 15 << LEFTSHIFT;
export const  EMaterial:number = 16 << LEFTSHIFT;
export const EPowerSpawn: number = 17 << LEFTSHIFT;
export const ENuker:number = 18 << LEFTSHIFT;

export var StructureMap: { [key: number]: string } = {};
StructureMap[ESpawn] = STRUCTURE_SPAWN;
StructureMap[EContainer] =   STRUCTURE_CONTAINER;
StructureMap[EExtension] =   STRUCTURE_EXTENSION;
StructureMap[ELab] =   STRUCTURE_LAB;
StructureMap[ELink] =  STRUCTURE_LINK;

StructureMap[ERoad] =  STRUCTURE_ROAD;
StructureMap[ERampart] =  STRUCTURE_RAMPART;
StructureMap[EMyWall] = STRUCTURE_WALL;

StructureMap[EStorage] =  STRUCTURE_STORAGE;
StructureMap[ETermial] =   STRUCTURE_TERMINAL;
StructureMap[ETower] =   STRUCTURE_TOWER;
StructureMap[EFactory] = STRUCTURE_FACTORY;
StructureMap[EObserver] = STRUCTURE_OBSERVER;
StructureMap[EPowerSpawn] = STRUCTURE_POWER_SPAWN;
StructureMap[ENuker] = STRUCTURE_NUKER;



const FastModulePlan:Record<string,IFVector2[]>={
    [STRUCTURE_SPAWN]:[{x:3,y:1},{x:3,y:0}],
    [STRUCTURE_TOWER]:[{x:3,y:3}],
    [STRUCTURE_STORAGE]:[{x:1,y:1}],
    [STRUCTURE_ROAD]:[{x:2,y:1},{x:1,y:2},{x:0,y:2},{x:0,y:1},{x:0,y:0},{x:1,y:0},{x:2,y:0}],
    [STRUCTURE_TERMINAL]:[{x:1,y:3}],
    [STRUCTURE_LAB]:[{x:3,y:2}],

};
export class Autoplainning
{

    static get MemoryPlans():{[key:string]:string}
    {
        return Memory.Data["Plans"] as any
    }

    // static Init()
    // {
    //     this.MemoryPlans =  Memory.Data["Plans"] ;
    //     if( this.MemoryPlans == undefined)
    //     {
    //         Memory.Data["Plans"]={}
    //         this.MemoryPlans = Memory.Data["Plans"];
    //     }
    // }
    // @cpu_used()
    // static Run()
    // {

    //     for(let key in Game.rooms)
    //     {
    //         const controller = Game.rooms[key].controller;


    //         if(controller && controller.my)
    //         {
    //             global.UserName = controller.owner?.username;
    //             if(this.MemoryPlans[key])
    //             {
    //                 continue;
    //             }
    //             const roomplan = this.GetTerrainlayoutByRoomname(key);
    //             this.MemoryPlans[key] = ZipRoomPlan.Zip(JSON.parse( roomplan));
    //             Memory.Debug[`重新计算布局${key}`] = Game.time;
    //         }
    //         // else
    //         // {
                
    //         // }
    //     }
    //     Memory.Data["Plans"] = this.MemoryPlans;
    // }

    public static createPlan(roomName:string,constspawn:boolean = false):boolean
    {
        const controller = Game.rooms[roomName].controller;
        if(controller && controller.my)
        {
            global.UserName = controller.owner?.username;
            if(this.MemoryPlans[roomName])
            {
                return true;
            }
            const roomplan = this.GetTerrainlayoutByRoomname(roomName,constspawn);
            //Memory.Debug[`计算布局${roomName}`] =roomplan;
            this.MemoryPlans[roomName] = ZipRoomPlan.Zip(JSON.parse( roomplan));
            // Memory.Debug[`重新计算布局${roomName}`] = Game.time;
            return true;
        }
        return false;
    }
    public static rebuildPlan(roomName:string,):boolean
    {
        const controller = Game.rooms[roomName].controller;
        if(controller && controller.my)
        {
            Autoplainning.clearRoomPlan(roomName);

            return Autoplainning.createPlan(roomName);
        }
        return false;
    }
    private static clearRoomPlan(roomName:string)
    {
        if( Memory.Data["Plans"] &&  Memory.Data["Plans"][roomName] )
        {
            delete Memory.Data["Plans"][roomName];
        }
        return Memory.Data["Plans"][roomName];
    }
    static InquireRoomplan(roomName:string):string|undefined
    {
        if(! Memory.Data["Plans"] )
        {
            Memory.Data["Plans"]={};
            return undefined;
        }
        return Memory.Data["Plans"][roomName];
    }

    public static GetTerrainlayoutByRoomname(curroom: string,constspawn:boolean = false): string
    {
        let terrain = JSON.stringify( this.GetTerrainBuffer(curroom));
        
        if(constspawn || Object.keys(Game.rooms).length==1)
        {
            const spawns = Game.rooms[curroom].find(FIND_MY_SPAWNS);
            const firstspawn = _.min(spawns,item=>item.pos.x);
            const offset={x:2,y:1}
            if(spawns.length>0)
            {
               return  global.wasmLib.GetTerrainModuleWithCenter(terrain,firstspawn.pos.x+offset.x,firstspawn.pos.y+offset.y);
            }
            if(Game.flags[curroom])
            {
                const firstspawnpos = Game.flags[curroom].pos;
                return  global.wasmLib.GetTerrainModuleWithCenter(terrain,firstspawnpos.x+offset.x,firstspawnpos.y+offset.y);
            }
        }
        
        return global.wasmLib.GetTerrainModule(terrain);
     }
     public static GetTerrainBuffer(curroom: string): Array<number>
    {
   
        var rawdata = (new Room.Terrain(curroom)).getRawBuffer();
        {
            if (Game.rooms[curroom].controller)
            {
                let controllerpos = (Game.rooms[curroom].controller as StructureController).pos;
                let idx = controllerpos.x + controllerpos.y * 50;
                rawdata[idx] = rawdata[idx] | (14 << 2);
            }

        }
        {

            let sources = Game.rooms[curroom].find(FIND_SOURCES);
            for (let key in sources)
            {
                let tmppos = sources[key].pos;
                let idx = tmppos.x + tmppos.y * 50;
                rawdata[idx] = rawdata[idx] | (15 << 2);
            }
        }
        {
            let minerials = Game.rooms[curroom].find(FIND_MINERALS);
            for (let key in minerials)
            {
                let tmppos = minerials[key].pos;
                let idx = tmppos.x + tmppos.y * 50;
                rawdata[idx] = rawdata[idx] | (16 << 2);
            }
         }
         var array = Array.from(rawdata);
         return array;
        // return rawdata;
    }
    // public static FindRoad(posstart:RoomPosition,posend:RoomPosition,roomName?:string)
    // {
    //     const roadpath = StationNetwork.getInstance..searchRoadcache(posstart,{pos:posend,range:1},{});
    //     // const structureRoadPositions  = UtilsHelper.deserializePath({pos:posstart,cache:roadpath.cache});


    //     return roadpath;
    // }
    /**
     * 外矿布局
     * @param SourcePos 
     * @returns 
     */
    public static CreateOutSourcePlan(SourcePos:RoomPosition)
    {
        const aroundpos = SourcePos.getFreeSpace(1);
        const ModuleType="outsource"
        const MinePlan:IModulePlan = {
            type:`${ModuleType}_${SourcePos.x}_${SourcePos.y}`,
            pos:SourcePos,
            structures:{container:[aroundpos[0]]},
        }
        return MinePlan;
    }
    /**
     * 控制器布局
     * @param pos 控制器坐标
     
     * @returns 
     */
    public static CreateControllerPlan(pos:RoomPosition)
    {
        const findPlacePosition=(pos:RoomPosition,range:number)=>
        {
            const grouppositions = PositionHelper.findRingOfPosition(pos,range);
            const max = _.max(grouppositions,e=>e.length);
            if(max.length>5)
            {
                return max;
            }
            return undefined;
        }
        const getSitePosition=(p:RoomPosition)=>
        {
            let poss = findPlacePosition(p,3);
            if(!poss)
            {
                poss = findPlacePosition(p,2);
            }
            if(poss)
            {
                const mid = Math.floor(poss.length/2);
                return [poss[mid-1],poss[mid],poss[mid+1]]
            }
            return []
        }
        return getSitePosition(pos);
    }

    public static FindSafeRegion(roomName:string,ramparts:IFVector2[],center:IFVector2):IFVector2[]
    {
        const terrain = this.GetTerrainBuffer(roomName);
        const rampart_1d = _.map(ramparts,e=>e.x+e.y*50);
        const center_1d = center.x+center.y*50;
        const safe_regions = global.wasmLib.getSafeRegion(JSON.stringify(terrain),JSON.stringify(rampart_1d),center_1d);
        return _.map(safe_regions,e=>{return {x:e%50,y:Math.floor(e/50)}});
    }

    /**
     * @descript 快速升级布局
     * @param roomName
     */
    public static CreateFastUpgraderPlan(roomName:string)
    {

        const room = Game.rooms[roomName];
        if(!room || !room.controller)
        {
            return false;
        }
        // source 周围一圈不能放
        const source = global.world.PollSource(roomName);
        const block_map:Record<number,boolean>={};
        if(source)
        {
            for(const e of source.cacheData)
            {
                const poss = e.pos.getFreeSpace();
                for(const p of poss)
                {
                    block_map[p.x+p.y*50]=true;
                }
            }
        }
        const result=  planningHelper.fastUpgradePlanMatrix(room.controller.pos,block_map);

        if(result)
        {
            const plan = this.TransformFastUpgraderPlan(result,room.controller.pos);
            return {matrix:result,plan:plan}
        }
        return false;
    }

    /**
     * @descript 快速升级布局
     * @param roomName
     */
     public static TransformFastUpgraderPlan( transform:Matrix3,controllerpos:RoomPosition)
     {

         const absPlan:Record<string,IFVector2[]>={};
         for(const key in FastModulePlan)
         {
            absPlan[key]= _.map(FastModulePlan[key],e=>transform.TransltePoint(e) );
         }
         const MinePlan:IModulePlan = {
                    type:`FastUpgradeEntity`,
                    pos:controllerpos,
                    structures:absPlan,
                }
        return MinePlan;
     }
}
